package com.eastfair.security.aspect;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eastfair.annotation.annotation.base.BaseControllerInfo;
import com.eastfair.annotation.annotation.base.IgnoreResponseBodyAdvice;
import com.eastfair.annotation.annotation.security.PreAuth;
import com.eastfair.annotation.annotation.tenant.TenantAuth;
import com.eastfair.auth.api.AuthServiceFeign;
import com.eastfair.auth.api.UserAccountServiceFeign;
import com.eastfair.cache.auth.InterfaceCacheKeyBuilder;
import com.eastfair.cache.auth.PermissionCacheKeyBuilder;
import com.eastfair.cache.repository.CacheOps;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextConstants;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.context.StaticContextUtil;
import com.eastfair.core.dynamic.DynamicAnno;
import com.eastfair.core.dynamic.DynamicData;
import com.eastfair.core.exception.BizException;
import com.eastfair.core.exception.ForbiddenException;
import com.eastfair.core.exception.UnauthorizedException;
import com.eastfair.core.exception.code.ExceptionCode;
import com.eastfair.core.handler.DataScopeHandler;
import com.eastfair.core.languagedynamic.LanguageDynamicAnno;
import com.eastfair.core.model.CacheKey;
import com.eastfair.core.model.DataIsolationModel;
import com.eastfair.core.model.DataScopeEnum;
import com.eastfair.core.model.SystemTagEnum;
import com.eastfair.core.utils.HeaderUtil;
import com.eastfair.core.utils.StrPool;
import com.eastfair.model.DataIsolationVo;
import com.eastfair.projectcore.enumeration.DataIsolationDataScopeEnum;
import com.eastfair.properties.IgnoreProperties;
import com.eastfair.security.config.DynamicParameterConfig;
import com.eastfair.security.constant.ValueConstant;
import com.eastfair.security.distionarydynamic.DistionaryDynamicAnno;
import com.eastfair.security.handler.DataIsolactionHandler;
import com.eastfair.security.util.TenantUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.core.env.Environment;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.xnio.channels.SuspendableAcceptChannel;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static com.eastfair.core.base.R.SUCCESS_CODE;


/**
 * controller请求切面操作
 * Created by ligang on 2010/03/02
 */
@Aspect
//@Component
@Order(2)
@Slf4j
public class UrlSecurityPreAuthAspect implements ApplicationContextAware {

    /**
     * 表达式处理
     */
    private static final ExpressionParser SP_EL_PARSER = new SpelExpressionParser();
    private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
    private final VerifyAuthFunction verifyAuthFunction;

    public UrlSecurityPreAuthAspect(VerifyAuthFunction verifyAuthFunction) {
        this.verifyAuthFunction = verifyAuthFunction;
    }

    //    public UrlSecurityPreAuthAspect() {
//    }
    private ApplicationContext ac;

    @Autowired
    TenantUtil tenantUtil;

    @Autowired
    UserAccountServiceFeign userAccountServiceFeign;

    @Autowired
    AuthServiceFeign authServiceFeign;

    @Autowired
    DistionaryDynamicAnno distionaryDynamicAnno;

    @Autowired
    DataIsolactionHandler dataIsolactionHandler;

    @Autowired
    ValueConstant valueConstant;

    @Autowired
    private CacheOps cacheOps;

    @Value("${com.eastfair.systemScene}")
    private String projectSystemScene;

    @Autowired
    private DynamicParameterConfig dynamicParameterConfig;


//    expression=”execution(* pp.business.*.*(..)) or execution(* pp.business.impl.*.*(..))”

    @Pointcut("execution( * com.eastfair..*.controller..*(..))")
    public void BindingResult() {
    }

    @After("BindingResult()")
    public void after(JoinPoint joinPoint) {
        log.info("after is execute");
    }

    @AfterReturning(value = "BindingResult()", returning = "rvt")
    public void AfterExec(JoinPoint joinPoint, Object rvt) {
        //controller报错不走这个方法
        log.info("AfterExec is execute");
        Map<String, Object> headerMap = HeaderUtil.getHeaderMap();
        log.info("controller执行结束，header is {}", JSONObject.toJSONString(headerMap));
    }

    @Around("BindingResult()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return joinPoint.proceed();
        }
        //组装BaseControllerInfo vo按需返回
        assembleBaseControllerInfo(joinPoint);
        HttpServletRequest request = attributes.getRequest();
        String url = request.getRequestURI(); // 这个方法只能获得不包含参数的请求url，且只包含相对路径
        String method = request.getMethod();
        log.info("url is {} , mehtod is {}", url, method);
        //设置全局变量
        globalVariable(request);
        //清除不需要废弃的属性
        clearWasteParam();
        //如果跨系统调用服务，则切换目标服务的系统id
        assembleSubSystemId();
        //接口权限判断
        if (dynamicParameterConfig.getInterfacePrimark()) {
            boolean interfacePan = validateInterface(ContextUtil.getUserId(), url);
            if (!interfacePan) {
                //没有接口权限
                throw new UnauthorizedException(ExceptionCode.NO_PERMISSION.getCode(), ExceptionCode.NO_PERMISSION.getMsg());
            }
        }
        String gateUrl = ContextUtil.getGatewayUrl();
        String gatewayMethod = ContextUtil.getGatewayMethod();
        //组装脱敏数据
        assembleDesensitizerData(url, method, gateUrl, gatewayMethod);

        //组装脱敏数据
        String disenstizerEnable = request.getHeader(ContextConstants.IS_DISENSTIZER_ENABLED);
        if (StringUtils.isNotBlank(disenstizerEnable) && "1".equals(disenstizerEnable)) {
            ContextUtil.setDisenstizerEnabled("1");
        }

        log.info("systemScene is {}", ContextUtil.getSystemScene());
        //记录MDC的行为日志
        MDC.put(ContextConstants.JWT_KEY_USER_ID, ContextUtil.getUserId() + "");
        //用户姓名
        MDC.put(ContextConstants.JWT_KEY_NAME, ContextUtil.getName());
        //存入MDC用于全局log缓存
        MDC.put(ContextConstants.LOG_TRACE_ID, ContextUtil.getTrace());
        //ip地址
        MDC.put(ContextConstants.IP_HEADER, StaticContextUtil.getIpAddr());

        //权限处理
        handleAuth(joinPoint);

        //多租户处理
        handleTenantAuth(joinPoint);

        log.info("UrlSecurityPreAuthAspect aop teamId is {}  subsystemId is {} ", ContextUtil.getTeamId(), ContextUtil.getSubSystemId());
        Object obj = joinPoint.proceed();
        //字典翻译
        distionaryData(obj);
        return obj;
    }

    /**
     * 组装脱敏数据
     *
     * @param url
     * @param method
     * @param gateUrl
     * @param gatewayMethod
     */
    public void assembleDesensitizerData(String url, String method, String gateUrl, String gatewayMethod) {
        try {
            String gateUrl2 = gateUrl.substring(1);
            gateUrl2 = gateUrl2.substring(gateUrl2.indexOf("/"));
            if (url.equals(gateUrl2) && method.equals(gatewayMethod) && !isIgnore(gateUrl) && valueConstant.getDesensitizerEnabled()) {
                ContextUtil.setDisenstizerEnabled("1");
            }
        } catch (Exception e) {
        }
    }

    public boolean isIgnore(String path) {
        List<String> urlList = valueConstant.getExcludeUrl();
        if (CollectionUtil.isEmpty(urlList)) {
            return false;
        }
        return urlList.stream().anyMatch(url -> (path.startsWith(url) && IgnoreProperties.isEnd(path, url)) || new AntPathMatcher().match(url, path));
    }


    public void distionaryData(Object obj) {
        Long l = System.currentTimeMillis();
        //字典翻译
        if (obj instanceof R) {
            R result = (R) obj;
            if (SUCCESS_CODE == result.getCode()) {
                //data数据
                if (result.getData() != null) {
                    //判断是否是分页数据  PageData
                    if (IPage.class.getName().equals(result.getData().getClass().getName())) {
                        IPage pageData = (IPage) result.getData();
                        List listObject = pageData.getRecords();
                        distionaryDynamicAnno.executeSimplVo(listObject);
                        pageData.setRecords(listObject);
                    } else if (Page.class.getName().equals(result.getData().getClass().getName())) {
                        Page pageData = (Page) result.getData();
                        List listObject = pageData.getRecords();
                        distionaryDynamicAnno.executeSimplVo(listObject);
                        pageData.setRecords(listObject);
                    } else {
                        Object object = result.getData();
                        distionaryDynamicAnno.executeSimplVo(object);
                    }
                }
            }
        }
//        distionaryDynamicAnno.removeData();
        log.info("字典耗时：" + (System.currentTimeMillis() - l));
    }

    /**
     * 设置系统id
     */
    public void assembleSubSystemId() {
        Long systemId = dataIsolactionHandler.switchSystemId();
        if (systemId != null && !systemId.equals(ContextUtil.getSubSystemId())) {
            ContextUtil.setSubSystemId(systemId);
        }
        //系统id为空，说明是定时器，则通过系统标识
        if (ContextUtil.getSubSystemId() == null) {
            Long subSystemId = dataIsolactionHandler.assmableSystemId(ContextUtil.getSystemScene());
            ContextUtil.setSubSystemId(subSystemId);
        }
    }

    /**
     * 设置全局变量
     *
     * @param request
     */
    public void globalVariable(HttpServletRequest request) {
        //将request信息转全局变量
        String account = request.getHeader(ContextConstants.JWT_KEY_ACCOUNT);
        String userid = request.getHeader(ContextConstants.JWT_KEY_USER_ID);
        String name = request.getHeader(ContextConstants.JWT_KEY_NAME);

        String realName = request.getHeader(ContextConstants.JWT_KEY_REAL_NAME);

        String isAdmin = request.getHeader(ContextConstants.JWT_KEY_IS_ADMIN);
        String isSuperAdmin = request.getHeader(ContextConstants.JWT_KEY_IS_SUPER_ADMIN);

        String projectid = request.getHeader(ContextConstants.JWT_KEY_PROJECT_ID);
        String trace = request.getHeader(ContextConstants.LOG_TRACE_ID);

        //展会id
        String exhibitionId = request.getHeader(ContextConstants.EXHIBITION_ID);
        //语言环境
        String languageType = request.getHeader(ContextConstants.LANGUAGE_TYPE);

        //语言环境
        String terminalDevice = request.getHeader(ContextConstants.TERMINAL_DEVICE);
        //语言环境
        String terminalType = request.getHeader(ContextConstants.TERMINAL_TYPE);
        //使用主体类型
        String subjectType = request.getHeader(ContextConstants.SUBJECT_TYPE);
        //系统场景
        String systemScene = request.getHeader(ContextConstants.SYSTEM_SCENE);
        //系统id
        String subsystemId = request.getHeader(ContextConstants.JWT_KEY_SUBSYSTEM_ID);

        //团队id
        String teamId = request.getHeader(ContextConstants.JWT_KEY_TEAM_ID);


        //归属系统
        String menuAffiliation = request.getHeader(ContextConstants.MENU_AFFILIATION);
        //场景
        String menuScene = request.getHeader(ContextConstants.MENU_SCENE);
        //数据权限数据
        String dataScopeOfUserId = request.getHeader(ContextConstants.DATA_SCOPE_OF_USERID);
        //是否内部調用
        String isFeign = request.getHeader(ContextConstants.FEIGN);
        //是否需要多租户隔离
        String isTenantIgnore = request.getHeader(ContextConstants.IS_SYSTEM_OLATION_IGNORE);

        /**
         * 网关 -请求地址
         */
        String gatewayUrl = request.getHeader(ContextConstants.GATEWAY_RQUEST_URL);
        /**
         * 网关 -请求方法
         */
        String gatewayMethod = request.getHeader(ContextConstants.GATEWAY_RQUEST_METHOD);


        String isIgnoreUrl = request.getHeader(ContextConstants.IS_IGNORE_URL);


        if (StringUtils.isNotBlank(account)) {
            ContextUtil.setAccount(account);
        }
        if (StringUtils.isNotBlank(userid)) {
            ContextUtil.setUserId(Long.parseLong(userid));
        }
        if (StringUtils.isNotBlank(name)) {
            ContextUtil.setName(name);
        }
        if (StringUtils.isNotBlank(projectid)) {
            ContextUtil.setProjectId(Long.parseLong(projectid));
        }
        if (StringUtils.isNotBlank(trace)) {
            ContextUtil.setTrace(trace);
        }

        if (StringUtils.isNotBlank(exhibitionId)) {
            ContextUtil.setExhibitionId(Long.parseLong(exhibitionId));
        }

        /**
         * 语言环境(cn/en)
         */
        if (StringUtils.isNotBlank(languageType)) {
            ContextUtil.setLanguageType(languageType);
        }

        /**
         * 请求来源版本信息
         */
        if (StringUtils.isNotBlank(terminalDevice)) {
            ContextUtil.setTerminalDevice(terminalDevice);
        }
        /**
         * 请求来源类型 （web/app/mini_programs）
         */
        if (StringUtils.isNotBlank(terminalType)) {
            ContextUtil.setTerminalType(terminalType);
        }

        /**
         * 指定多数据源信息
         */
        if (ContextUtil.getTenantId() != null) {
            ContextUtil.setTenant(tenantUtil.getTenant());
        }

        /**
         * 系统场景{P_VENUE:场馆业务管理系统;P_CERTIFICATE:证件管理系统;P_COMPOSITE_VENUE:综合-场馆管理; P_COMPOSITE_COURT:综合-主场管理;P_COMPOSITE_PRODUCER:综合-搭建商管理;P_COMPOSITE_TRANSPORT:综合-主运管理;P_COMPOSITE_TRADE:综合-商旅管理;P_COMPOSITE_MATING:综合-配套商管理;P_PAY:支付系统;P_EXHIBITOR_SELF:展商自服务;P_CATERINGAPP:餐饮小程序;P_CATERING:餐饮后台服务;P_PORTAL_OUT_VENUE:对外门户-场馆后台;P_PORTAL_OUT_OPERATION:对外门户-运营后台;P_PORTAL_IN_WORK:内部门户-工作后台;P_PORTAL_IN_WORKAPP:内部门户-工作APP;P_OPERATION_CENTER:智慧运营中心系统;P_VISITOR_FRONT:访客前台系统;P_VISITOR_BACK:访客后台系统;P_R_EXHIBITOR:展商组;P_R_SPONSOR:主办组;P_R_BUILDER:搭建商组;P_R_COURT:主场组;P_R_TRANSPORT:主运组;P_R_BOOKING:场馆方组;P_R_REPAST:餐饮方组;EXHIBITOR:展商;EXHIBITOR_STAFF:展商员工;SPONSOR:主办;SPONSOR_STAFF:主办员工;BUILDER:搭建商;BUILDER_STAFF:搭建商员工;COURT:主场;COURT_STAFF:主场员工;TRANSPORT:主运;TRANSPORT_STAFF:主运员工;BOOKING:场馆方;BOOKING_STAFF:场馆方员工;REPAST:餐饮方;REPAST_STAFF:餐饮方员工;STAFF:员工;OTHER:其他}", replace = {"厦门智慧场馆_P", "场馆业务管理系统_P_VENUE", "证件管理系统_P_CERTIFICATE", "综合-场馆管理_P_COMPOSITE_VENUE", "综合-主场管理_P_COMPOSITE_COURT", "综合-搭建商管理_P_COMPOSITE_PRODUCER", "综合-主运管理_P_COMPOSITE_TRANSPORT", "综合-商旅管理_P_COMPOSITE_TRADE", "综合-配套商管理_P_COMPOSITE_MATING", "支付系统_P_PAY", "展商自服务_P_EXHIBITOR_SELF", "餐饮小程序_P_CATERINGAPP", "餐饮后台服务_P_CATERING", "对外门户-场馆后台_P_PORTAL_OUT_VENUE", "对外门户-运营后台_P_PORTAL_OUT_OPERATION", "内部门户-工作后台_P_PORTAL_IN_WORK", "内部门户-工作APP_P_PORTAL_IN_WORKAPP", "智慧运营中心系统_P_OPERATION_CENTER", "访客前台系统_P_VISITOR_FRONT", "访客后台系统_P_VISITOR_BACK"}
         */
        if (StringUtils.isNotBlank(systemScene)) {
            ContextUtil.setSystemScene(systemScene);
        }

        if (StringUtils.isNotBlank(realName)) {
            ContextUtil.setRealName(realName);
        }

        if (StringUtils.isNotBlank(isAdmin)) {

            ContextUtil.setIsAdmin(Integer.parseInt(isAdmin));
        }

        if (StringUtils.isNotBlank(isSuperAdmin)) {

            ContextUtil.setIsSuperAdmin(Integer.parseInt(isSuperAdmin));
        }

        /**
         * 系统id
         */
        if (subsystemId != null) {
            ContextUtil.setSubSystemId(Long.parseLong(subsystemId));
        }

        /**
         * 团队id
         */
        if (teamId != null) {
            ContextUtil.setTeamId(Long.parseLong(teamId));
        }


        if (StringUtils.isNotBlank(menuAffiliation)) {
            ContextUtil.setMenuAffiliation(menuAffiliation);
        }
        if (StringUtils.isNotBlank(menuScene)) {
            ContextUtil.setMenuScene(menuScene);
        }
        if (StringUtils.isNotBlank(dataScopeOfUserId)) {
            ContextUtil.setDataScopeOfUserId(dataScopeOfUserId);
        }

        if (StringUtils.isNotBlank(isFeign)) {
            ContextUtil.setXFeign(isFeign);
        }

        if (StringUtils.isNotBlank(isTenantIgnore)) {
            ContextUtil.setIsSystemOlationIgnore(Boolean.valueOf(isTenantIgnore));
        }

        if (StringUtils.isNotBlank(gatewayUrl)) {
            ContextUtil.setGatewayUrl(gatewayUrl);
        }
        if (StringUtils.isNotBlank(gatewayMethod)) {
            ContextUtil.setGatewayMethod(gatewayMethod);
        }
        if (StringUtils.isNotBlank(isIgnoreUrl)) {
            ContextUtil.setIsIgnoreUrl(Integer.parseInt(isIgnoreUrl));
        }
    }

    /**
     * 清除废弃的属性，
     * 如
     * 1 系统级别不能有teamid
     * 2 systemScene 系统标识替换为本服务的系统标识
     */
    public void clearWasteParam() {
        if (DataIsolationModel.getSelfTag() != null && SystemTagEnum.COMMON.eq(DataIsolationModel.getSelfTag())) {
            //公共服务，不清除
            return;
        }
        String staticProjectSystemDataScope = StaticContextUtil.getStaticProjectSystemDataScope();
        List<Map> mapList = JSONArray.parseArray(staticProjectSystemDataScope, Map.class);
        if (CollectionUtil.isEmpty(mapList)) {
            return;
        }
        //替换为本系统标识
        // TODO: 2023/2/28 正常情况，应该是链路到哪个系统，系统标识就是哪个系统，但业务已经写成全链路共享，导致一旦变化，业务改动会很多，所以暂时注释
//        ContextUtil.setSystemScene(StaticContextUtil.getProjectSystemScene());
        for (Map map : mapList) {
            String dataScope = (String) map.get("dataScope");
            if (DataIsolationDataScopeEnum.SUB_SYSTEM.getCode().equals(dataScope)) {
                //项目是系统级别，不需要团队id
                ContextUtil.setTeamId(null);
            }
        }

    }

    /**
     * 处理权限
     *
     * @param joinPoint 切点
     */
    private void handleAuth(ProceedingJoinPoint joinPoint) {
        MethodSignature ms = (MethodSignature) joinPoint.getSignature();
        Method method = ms.getMethod();
        // 读取权限注解，优先方法上，没有则读取类
        PreAuth preAuth = null;
        if (joinPoint.getSignature() instanceof MethodSignature) {
            method = ((MethodSignature) joinPoint.getSignature()).getMethod();
            if (method != null) {
                preAuth = method.getAnnotation(PreAuth.class);
            }
        }
        String methodName = method != null ? method.getName() : "";
        // feign 远程调用
        if (isFeign(methodName)) {
            return;
        }

        // 读取目标类上的权限注解
        PreAuth targetClass = joinPoint.getTarget().getClass().getAnnotation(PreAuth.class);


        // 方法上校验
        if (preAuth == null || targetClass == null) {
            log.debug("执行方法[{}]无需校验权限", methodName);
            return;
        }
        // 方法上禁用
        if (preAuth != null && !preAuth.enabled()) {
            log.debug("执行方法[{}]无需校验权限", methodName);
            return;
        }
        // 类上禁用
        if (targetClass != null && !targetClass.enabled()) {
            log.debug("执行方法[{}]无需校验权限", methodName);
            return;
        }

        String condition = getCondition(preAuth, targetClass);
        if (StrUtil.isBlank(condition)) {
            return;
        }
        Boolean hasPermit = invokePermit(joinPoint, method, condition);
        if (!hasPermit) {
            throw ForbiddenException.wrap(ExceptionCode.UNAUTHORIZED.build("执行方法[%s]需要[%s]权限", methodName, condition));
        }
    }


    /**
     * 多租户权限
     *
     * @param joinPoint 切点isFeign
     */
    private void handleTenantAuth(ProceedingJoinPoint joinPoint) {
        if (isFeign("")) {
            //内部调用，不需要校验是否使用多租户权限
            return;
        }
        MethodSignature ms = (MethodSignature) joinPoint.getSignature();
        Method method = ms.getMethod();
        log.info("method is {}", method.getName());
        TenantAuth preAuth = method.getAnnotation(TenantAuth.class);
        ContextUtil.setIsSystemOlationIgnore(false);
        if (ContextUtil.getIsSuperAdmin() != null && BusinessConstant.YES == ContextUtil.getIsSuperAdmin()) {
            if (!"C_AUTH".equals(StaticContextUtil.getProjectSystemScene())) {
                //管理员则查询所有数据，忽略多租户
                ContextUtil.setIsSystemOlationIgnore(true);
            }
        }

        if (preAuth != null) {
            if (preAuth.enabled()) {
                ContextUtil.setIsSystemOlationIgnore(preAuth.enabled());
            }
        }
    }

    private boolean isFeign(String methodName) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes != null) {
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            if (request != null) {
                if (StrPool.TRUE.equals(request.getHeader(ContextConstants.FEIGN))) {
                    log.debug("内部调用方法[{}]无需校验权限", methodName);
                    return true;
                }
            }
        }
        return false;
    }


    @Nullable
    private Boolean invokePermit(ProceedingJoinPoint point, Method method, String condition) {
        StandardEvaluationContext context = new StandardEvaluationContext(verifyAuthFunction);
        Expression expression = SP_EL_PARSER.parseExpression(condition);
        // 方法参数值
        Object[] args = point.getArgs();
        context.setBeanResolver(new BeanFactoryResolver(ac));
        for (int i = 0; i < args.length; i++) {
            MethodParameter mp = new SynthesizingMethodParameter(method, i);
            mp.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
            context.setVariable(mp.getParameterName(), args[i]);
        }
        return expression.getValue(context, Boolean.class);
    }

    @Nullable
    private String getCondition(PreAuth preAuth, PreAuth targetClass) {
        String condition = preAuth == null ? targetClass.value() : preAuth.value();
        if (condition.contains(StrPool.BRACE)) {
            if (targetClass != null && StrUtil.isNotBlank(targetClass.replace())) {
                condition = StrUtil.format(condition, targetClass.replace());
            } else {
                // 子类类上边没有 @PreAuth 注解，证明该方法不需要简要权限
                return null;
            }
        }
        return condition;
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        this.ac = applicationContext;
    }


    /**
     * 组装BaseControllerInfo
     */
    public void assembleBaseControllerInfo(ProceedingJoinPoint joinPoint) {
        MethodSignature ms = (MethodSignature) joinPoint.getSignature();
        Method method = ms.getMethod();
        // 读取权限注解，优先方法上，没有则读取类
        BaseControllerInfo baseControllerInfo = null;
        if (method != null) {
            baseControllerInfo = method.getAnnotation(BaseControllerInfo.class);
            if (baseControllerInfo != null) {
                if (baseControllerInfo.voGroup() != null) {
                    Class[] classes = baseControllerInfo.voGroup();
                    if (classes.length > 0) {
                        DynamicData.setGroupClassThreadLocal(classes[0]);
                    }
                }
                DynamicData.setBaseControllerInfoThreadLocal(baseControllerInfo);
            }
        }
    }


//    public static void main(String[] args) {
////        SpelExpressionParser parser = new SpelExpressionParser();
//////        Expression expression = parser.parseExpression("10*5+8*(19+2)/6");
////        Expression expression = parser.parseExpression("10*5+8*(19+2)/6");
////
////        String context = "";
////        List listOfLists = (List) parser.parseExpression("{}add").getValue(context);
////        Integer value = (Integer) expression.getValue();
////        System.out.println(listOfLists);
//
//        List<String> list = new ArrayList<>();
//        list.add("/userAccount/login2");
//        list.add("/userAccount/login23");
//        list.add("/userAccount/login/**");
//        System.out.println(isAuthOfmethod(list, "/userAccount/login/aaa"));
//    }


    /**
     * 接口权限判断
     *
     * @return
     */
    public boolean validateInterface(Long userId, String path) {
        //feign内部调用不校验
        if (isFeign("")) {
            return true;
        }
        if (userId == null || userId == 0) {
            //没有用户信息不校验
            return true;
        }
        log.info("isSuperAdmin is {} ,isIgnoreUrl is {}", ContextUtil.getIsSuperAdmin(), ContextUtil.getIsIgnoreUrl());
        if (ContextUtil.getIsSuperAdmin() != null && BusinessConstant.YES == ContextUtil.getIsSuperAdmin()) {
            //超级管理员不校验
            return true;
        }
        if (ContextUtil.getIsIgnoreUrl() != null && ContextUtil.getIsIgnoreUrl() == 1) {
            //过滤的url不校验
            return true;
        }


        if (CollectionUtil.isNotEmpty(dynamicParameterConfig.getInterfaceList())) {
            log.info("url is {} ,interfaceList is {}", path, JSONObject.toJSONString(dynamicParameterConfig.getInterfaceList()));
            //接口过滤的地址不校验
            Boolean pan = dynamicParameterConfig.getInterfaceList().stream().anyMatch(url -> (path.startsWith(url) && IgnoreProperties.isEnd(path, url)) || new AntPathMatcher().match(url, path));
            if (pan) {
                log.info("url is {} ,interfaceList is {}, result is {}", path, JSONObject.toJSONString(dynamicParameterConfig.getInterfaceList()), true);
                return true;
            }
        }
        return isAuthOfmethod(queryInterfaceList(userId), path);
    }

    /**
     * 查询用户接口角色
     *
     * @param userId
     * @return
     */
    public List<String> queryInterfaceList(Long userId) {
        String cachekeyName = (StringUtils.isNotBlank(ContextUtil.getSystemScene()) ? ContextUtil.getSystemScene() : "") + userId;
        CacheKey cacheKey = new InterfaceCacheKeyBuilder().key(cachekeyName);
        List<String> interfaceList = cacheOps.get(cacheKey);
        log.info("接口权限 key is {} , 集合 is {}", cacheKey, JSONObject.toJSONString(interfaceList));
        if (CollectionUtil.isEmpty(interfaceList)) {
            //重新加载信息
//            userAccountServiceFeign.loadUserInterface(userId);
//            interfaceList = cacheOps.get(cacheKey);
            return null;
        }
        return interfaceList;
    }

    /**
     * 是否有接口权限
     *
     * @param urlList
     * @param path
     * @return
     */
    public static boolean isAuthOfmethod(List<String> urlList, String path) {
        log.info("urlList is {}", JSONObject.toJSONString(urlList));
        if (CollectionUtil.isEmpty(urlList)) {
            return false;
        }
        return urlList.stream().anyMatch(url -> (path.startsWith(url) && IgnoreProperties.isEnd(path, url)) || new AntPathMatcher().match(url, path));
    }
}
